package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    //trade.html,myOrder.html ,list.html
    @Value("${authUrls.url}")
    private String authUrls;

    private AntPathMatcher antPathMatcher =new AntPathMatcher();

    /**
     * 执行过滤的方法
     * @param exchange
     * @param chain
     * @return
     * URL:http://www.gmall.com/index.html
     * URI:/index.html
     *
     * URL:localhost:80
     * URi: /api/product/inner/getSkuInfo/{skuId}
     *
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //获取请求资源的uri
        ServerHttpRequest request = exchange.getRequest();
        //获取uri
        String path = request.getURI().getPath();
        //匹配判断是否为内部接口 /**/inner/** (inner路径的请求时模块与模块之间的内部调用,不允许用户访问)
        if(antPathMatcher.match("/**/inner/**",path)){
            ServerHttpResponse response = exchange.getResponse();
            //响应内容，拒绝
            return out(response,ResultCodeEnum.PERMISSION);
        }

        //认证
        String userId=getUserId(request);
        //认证后，有三种结果  -1  “”  userId

        //-1被调用
        if("-1".equals(userId)){

            ServerHttpResponse response = exchange.getResponse();
            //响应内容，拒绝
            return out(response,ResultCodeEnum.PERMISSION);
        }

        //需要登录的uri
        if(antPathMatcher.match("/api/**/auth/**",path)){
            //判断
            if(StringUtils.isEmpty(userId)){
                //此时未登录
                ServerHttpResponse response = exchange.getResponse();
                //响应内容，拒绝
                return out(response,ResultCodeEnum.LOGIN_AUTH);
            }
        }

        /**
         * 白名单--必须要认证的内容 authUrls
         * trade.html,myOrder.html ,list.html
         * http://list.gmall.com/list.html?category3Id=61
         *
         */

        for (String uri : authUrls.split(",")) {

            if(path.contains(uri)&&StringUtils.isEmpty(userId)){

                //获取响应对象
                ServerHttpResponse response = exchange.getResponse();
                //重定向
                //状态
                response.setStatusCode(HttpStatus.SEE_OTHER);
                //location
                response.getHeaders().set(HttpHeaders.LOCATION,
                        "http://www.gmall.com/login.html?originUrl="+request.getURI());

                //重定向
                return response.setComplete();
            }
        }

        /**
         * 获取用户临时id
         */

        String userTempId=getUserTempId(request);

        //需求将userId存储到header头
        if(!StringUtils.isEmpty(userId)||!StringUtils.isEmpty(userTempId)){
            if(!StringUtils.isEmpty(userId)){

                request.mutate().header("userId",userId).build();
            }
            if(!StringUtils.isEmpty(userTempId)){

                request.mutate().header("userTempId",userTempId).build();
            }
            return chain.filter(exchange.mutate().request(request).build());
        }
        //放行
        return chain.filter(exchange);
    }

    /**
     * 获取临时id信息
     * @param request
     * @return
     */
    private String getUserTempId(ServerHttpRequest request) {
        String userTempId = request.getHeaders().getFirst("userTempId");
        //判断
        if(StringUtils.isEmpty(userTempId)){
            //获取cookie
            MultiValueMap<String, HttpCookie> cookies = request.getCookies();

            HttpCookie cookie = cookies.getFirst("userTempId");
            //判断
            if(cookie!=null){

                userTempId=cookie.getValue();
            }

        }
        return userTempId;
    }


    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 根据token获取用户id
     * @param request
     * @return
     */
    private String getUserId(ServerHttpRequest request) {
        //请求头
        String token = request.getHeaders().getFirst("token");

        //判断
        if(StringUtils.isEmpty(token)){

            //cookie
            MultiValueMap<String, HttpCookie> cookie = request.getCookies();
            //判断
            if(cookie!=null&&cookie.size()>0){

                if( cookie.getFirst("token")!=null){

                    token= cookie.getFirst("token").getValue();
                }


            }

        }

        //判断token是否存在
        if(StringUtils.isEmpty(token)){
            return "";

        }else{

            //从redis中获取数据
            String strUser = (String) redisTemplate.opsForValue().get(RedisConst.USER_LOGIN_KEY_PREFIX + token);

            if(!StringUtils.isEmpty(strUser)){
                //转换成
                JSONObject jsonObject = JSONObject.parseObject(strUser);
                //判断
                String redisIp = (String) jsonObject.get("ip");
                //获取当前的IP
                String gatwayIpAddress = IpUtil.getGatwayIpAddress(request);
                //判断
                if(gatwayIpAddress.equals(redisIp)){
                    return (String) jsonObject.get("userId");
                }else{
                    return "-1";
                }
            }
            return "";
        }
    }

    /**
     * 将处理信息，写到浏览器上
     * @param response
     * @param permission
     *
     * 中文乱码问题：
     *
     * 1.编码时，指定了UTF-8"
     *  内容“ 没有权限”
     * 2.解码时，也需要使用 UTF-8
     *
     *
     */
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum permission) {

        //生成响应内容
        Result<Object> result = Result.build(null, permission);
        //
        byte[] bytes = JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8);
        //获取DateBuffer
        DataBuffer wrap = response.bufferFactory().wrap(bytes);

        //处理中文乱码
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");

        return response.writeWith(Mono.just(wrap));
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
